﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.VisualStudio.Package;
using Microsoft.VisualStudio.TextManager.Interop;

namespace BlunderBrain.VisualStudio.AviSynth
{
    public class AviSynthLanguageService : LanguageService
    {
        private const string m_filterList = "AviSynth Script (*.avs)\n*.avs\nAviSynth Autoload Script (*.avsi)\n*.avsi";

        private LanguagePreferences m_languagePreferences = null;
        private AviSynthScriptEnvironment m_scriptEnvironment;
        private AviSynthTokenizer m_scanner;
        private AviSynthParser m_parser;

        public enum IconImageIndex
        {
            // Each icon type has 6 versions, corresponding to the following
            // access types.
            AccessPublic = 0,
            AccessInternal = 1,
            AccessFriend = 2,
            AccessProtected = 3,
            AccessPrivate = 4,
            AccessShortcut = 5,

            Base = 6,

            Class = Base * 0,
            Constant = Base * 1,
            Delegate = Base * 2,
            Enumeration = Base * 3,
            EnumMember = Base * 4,
            Event = Base * 5,
            Exception = Base * 6,
            Field = Base * 7,
            Interface = Base * 8,
            Macro = Base * 9,
            Map = Base * 10,
            MapItem = Base * 11,
            Method = Base * 12,
            OverloadedMethod = Base * 13,
            Module = Base * 14,
            Namespace = Base * 15,
            Operator = Base * 16,
            Property = Base * 17,
            Struct = Base * 18,
            Template = Base * 19,
            Typedef = Base * 20,
            Type = Base * 21,
            Union = Base * 22,
            Variable = Base * 23,
            ValueType = Base * 24,
            Intrinsic = Base * 25,
            JavaMethod = Base * 26,
            JavaField = Base * 27,
            JavaClass = Base * 28,
            JavaNamespace = Base * 29,
            JavaInterface = Base * 30,
            // Miscellaneous icons with one icon for each type.
            Error = 187,
            GreyedClass = 188,
            GreyedPrivateMethod = 189,
            GreyedProtectedMethod = 190,
            GreyedPublicMethod = 191,
            BrowseResourceFile = 192,
            Reference = 193,
            Library = 194,
            VBProject = 195,
            VBWebProject = 196,
            CSProject = 197,
            CSWebProject = 198,
            VB6Project = 199,
            CPlusProject = 200,
            Form = 201,
            OpenFolder = 202,
            ClosedFolder = 203,
            Arrow = 204,
            CSClass = 205,
            Snippet = 206,
            Keyword = 207,
            Info = 208,
            CallBrowserCall = 209,
            CallBrowserCallRecursive = 210,
            XMLEditor = 211,
            VJProject = 212,
            VJClass = 213,
            ForwardedType = 214,
            CallsTo = 215,
            CallsFrom = 216,
            Warning = 217,
        }

        // TODO: scriptenvironment (and parser?) has to be instantiated per source!

        public AviSynthLanguageService()
        {
            m_scriptEnvironment = new AviSynthScriptEnvironment();
            m_scanner = new AviSynthTokenizer();
            m_parser = new AviSynthParser();
        }

        public override string GetFormatFilterList()
        {
            return m_filterList;
        }

        public override LanguagePreferences GetLanguagePreferences()
        {
            if (m_languagePreferences == null)
            {
                m_languagePreferences = new LanguagePreferences(this.Site, this.GetLanguageServiceGuid(), this.Name);
                m_languagePreferences.Init();
            }

            return m_languagePreferences;
        }

        public override IScanner GetScanner(Microsoft.VisualStudio.TextManager.Interop.IVsTextLines buffer)
        {
            return m_scanner;
        }

        public override string Name
        {
            get { return "AviSynth"; }
        }

        public override AuthoringScope ParseSource(ParseRequest req)
        {
            AviSynthAuthoringScope scope = new AviSynthAuthoringScope();
            AviSynthParseRequest request = req as AviSynthParseRequest;

            switch (req.Reason)
            {
                case ParseReason.Check:
                    m_parser.FindScriptFunctions(request, scope);
                    bool result = m_parser.Parse(request, scope);
                    break;
                case ParseReason.CompleteWord:
                    m_parser.GetDeclarationsForCompletion(request, scope);
                    break;
                case ParseReason.MethodTip:
                    break;
            }
            return scope;

        }

        public override Source CreateSource(Microsoft.VisualStudio.TextManager.Interop.IVsTextLines buffer)
        {
            AviSynthSource source = new AviSynthSource(this, buffer, this.GetColorizer(buffer), new AviSynthScriptEnvironment());
            source.LastParseTime = 0; //Uncomment to activate automatic calls to ParseSource
            return source;
        }

        public override ParseRequest CreateParseRequest(Source s, int line, int idx, TokenInfo info, string sourceText, string fname, ParseReason reason, IVsTextView view)
        {
            bool sync = false;
            if (!this.Preferences.EnableAsyncCompletion)
                sync = true; //unless registry value indicates that sync ops always prefer async 

            AviSynthSource source = s as AviSynthSource;

            return new AviSynthParseRequest(line, idx, info, sourceText, fname, reason, view, source.CreateAuthoringSink(reason, line, idx), sync, source.ScriptEnvironment);
        }

        /*
        public override void OnIdle(bool periodic)
        {
            Source src = GetSource(this.LastActiveTextView);
            if (src != null && src.LastParseTime == Int32.MaxValue)
            {
                src.LastParseTime = 0;
            }

            base.OnIdle(periodic);
        }
         */ 
    }
}
